#include <sstream>
#include <iostream>
#include <fstream>
#include "DataPoint.h"

using namespace std;
/*******************************************************************/
CDataPoint::CDataPoint(void)
{
	m_id=0;
	m_img = NULL;
	m_image_file = "";
	m_class = "NONE";
	m_sz = cvRect(0,0,0,0);
	m_contourLength=0.00;
	m_contourArea=0.00;
	m_aspectRatio=0.00;
	m_memStorage = cvCreateMemStorage();
	m_contour = NULL;
	m_LineHist = NULL;
	m_CircleHist = NULL;
	m_sampleArea = 0;
	m_samplePerimeter = 0;
	
}
/*******************************************************************/
CDataPoint::~CDataPoint(void)
{
	FreeImage();
	cvClearMemStorage(m_memStorage);
	cvReleaseHist(&m_LineHist);
	cvReleaseHist(&m_CircleHist);
}	
/*******************************************************************/

/*******************************************************************/
void CDataPoint::LoadImage(void)
{
	FreeImage();
	string imgName = m_path+m_image_file;
	m_img = cvLoadImage(imgName.c_str());
}
/*******************************************************************/
void CDataPoint::LoadImageBW(void)
{
	FreeImage();
	string imgName = m_path+m_image_file;
	IplImage* tempImg = cvLoadImage(imgName.c_str());
	m_img = cvCreateImage(cvSize(tempImg->width,tempImg->height),tempImg->depth, 1);
	cvCvtColor(tempImg,m_img, CV_BGR2GRAY);
	if( tempImg != NULL )
	{
		cvReleaseImage(&tempImg);
	}
}
/*******************************************************************/
bool CDataPoint::ImageIsBW(void)
{
	bool retVal = false;
	if( NULL != m_img )
	{
		if( m_img->nChannels == 1 )
			retVal = true;
	}
	return retVal;
}
/*******************************************************************/
void CDataPoint::FreeImage(void)
{
	if( m_img != NULL )
	{
		cvReleaseImage(&m_img);
		m_img = NULL; 
	}
}
/*******************************************************************/
string CDataPoint::WriteForFile(void) 
{
	string retVal="";
	return retVal;
}
/*******************************************************************/
bool CDataPoint::ReadForFile( istream is )
{
	bool retVal = false;
	return retVal; 
}
/*******************************************************************/
CvSeq* CDataPoint::ExtractContourStats(void)
{
	bool retVal=false;
	if(!HasImage() || !ImageIsBW() )
	{
		LoadImageBW();
	}

	IplImage* temp = cvCreateImage(cvSize(m_img->width,m_img->height),m_img->depth,1);
	IplImage* temp2 = cvCreateImage(cvSize(m_img->width,m_img->height),m_img->depth,1);
	// need thresh
	cvCopy(m_img,temp);
	cvThreshold(temp,temp2,125,255, CV_THRESH_BINARY_INV);
	cvDilate(temp2,temp2,NULL,3);
	CvSeq* contour = NULL;
	CvSeq* best = NULL;
	double length=0.00;
	double best_l = 0.00;
	CvContourScanner scanner = cvStartFindContours( temp2,m_memStorage );//, sizeof(CvContour), CV_RETR_CCOMP);
	contour = cvFindNextContour( scanner );
	vector<CvSeq*> ctrs;

	while(contour)
	{
		length = cvContourPerimeter(contour);
		if( length > best_l )
		{
			best_l = length;
			best = contour;
		}
		contour = cvFindNextContour( scanner );
	}
	
	m_contour = best;
	cvReleaseImage(&temp);
	cvReleaseImage(&temp2);
	m_sz = cvBoundingRect(m_contour);
	m_sampleArea =  m_sz.width*m_sz.height;
	m_samplePerimeter = (2*m_sz.width)+(2*m_sz.height);
	m_aspectRatio = (float)m_sz.width/(float)m_sz.height;
	m_contourLength = (float)cvArcLength(m_contour);
	m_contourLength = m_contourLength/(float)m_samplePerimeter;
	m_contourArea = (float)cvContourArea(m_contour);
	m_contourArea = m_contourLength/((float)m_sampleArea);
	CvMoments moments;
	cvContourMoments(m_contour,&moments);
	cvGetHuMoments(&moments, &m_huMoments);

	return m_contour;
}
/*******************************************************************/
CvRect CDataPoint::GetSize(void)
{
	return m_sz;
}
/*******************************************************************/
IplImage * CDataPoint::GetEdgeImage(void)
{
	// we're just going to do a vanilla canny
	// nothing fancy
	if(!HasImage() || !ImageIsBW() )
	{
		LoadImageBW();
	}
	IplImage* temp = cvCreateImage(cvSize(m_img->width,m_img->height),IPL_DEPTH_8U,1);
	cvCanny(m_img,temp,50,150);
	return temp;
}
/*******************************************************************/
void CDataPoint::ExtractLineHistogram(void)
{
	IplImage * lineImg = GetEdgeImage(); 
	char * fname=NULL;
	fname = new char[48];
	//sprintf(fname,"DataPoint%iEdge.png",m_id);
	//cvSaveImage(fname,lineImg);
	double rho = 1; // don't discritize 
	double theta = CV_PI/180.0; // 2 degree increments 
	int thresh = 7; // minimum number of points on the line 
	double min_length = 3; // minimum length
	double min_space = 3; //distance btw colinear segments before separation 
	CvSeq* lhist = cvHoughLines2(lineImg,m_memStorage,CV_HOUGH_PROBABILISTIC, rho, theta, thresh, min_length, min_space); 
	printf( "Found %i points\n",lhist->total);
	// 2 dimensions, 10 degree increments and an equal number of spatial bins
	CvArr** histData = new CvArr*[2];
	histData[0]= cvCreateMat(lhist->total,1, CV_8U);// <-- CV_8U IS TOTAL BULLSHIT
	histData[1]= cvCreateMat(lhist->total,1, CV_8U);// <-- BUT IT WON'T WORK OTHERWISE
	
//	sprintf(fname,"EdgeHist%i.txt",m_id);
//	ofstream ofs;
//	ofs.open(fname);
	for( int i=0; i < lhist->total; i++)
	{
		CvPoint* points = (CvPoint*)cvGetSeqElem(lhist,i);
		double x = abs((double)(points[0].x-points[1].x));
		double y = abs((double)(points[0].y-points[1].y));
		double l = (sqrt((x*x+y*y))/((double)m_samplePerimeter));
		double a = (double)atan2(y,x);
		a = 360.00f*(a/(2*CV_PI));
		if( a < 0 )
		{
			a = 360.00f+a;
		}
		cvSet1D(histData[0],i,cvScalar(a));
		cvSet1D(histData[1],i,cvScalar(l));
//		ofs << l << "\t" << a << endl;
		//printf("Point (%i,%i)->(%i,%i) -> length: %f angle: %f \n",points[0].x, points[0].y,points[1].x,points[1].y, l, a);
		//cvDrawLine(lineImg,points[0],points[1],cvScalarAll(127));
	}
//	ofs.close();
	int bins[] = {6,3};
	m_LineHist = cvCreateHist(2,bins,CV_HIST_ARRAY);
	cvCalcArrHist(histData,m_LineHist);
	cvNormalizeHist(m_LineHist,1.00);
	for(int i=0; i<2;i++)
	{
		CvArr* temp = histData[i];
		cvRelease(&temp);
	}
	if( NULL != histData )
		delete [] histData; 

	sprintf(fname,"DataPoint%iEdgeLines.png",m_id);
	//cvSaveImage(fname,lineImg);

	if( NULL != fname )
		delete [] fname;
	cvReleaseImage(&lineImg);
}
/*******************************************************************/
void CDataPoint::ExtractCircleHistogram(void)
{
	IplImage * lineImg = GetEdgeImage(); 
	double resolution = 1;
	double min_dist = 10.00f; // 10 pixels btw the center of each circle
	double p1 = 100; // lower canny bound 
	double p2 = 10; // threshold for accumulator plane
	double min_r = 10.00f; // minimum radius
	double max_r = lineImg->width;
	char * fname=NULL;
	fname = new char[48];
	//sprintf(fname,"DataPoint%iEdge.png",m_id);
	CvSeq* cHist = cvHoughCircles(lineImg,m_memStorage,CV_HOUGH_GRADIENT, resolution, min_dist, p1, p2 ); 

	//	printf( "Found %i points\n",cHist->total);
	int bins[] = {10};
	m_CircleHist = cvCreateHist(1,bins,CV_HIST_ARRAY);
	CvArr** histData = new CvArr*[1];
	if( cHist->total > 0 )
	{
//		sprintf(fname,"CircleHist%i.txt",m_id);
//		ofstream ofs;
//		ofs.open(fname);
		histData[0]= cvCreateMat(cHist->total,1, CV_8U);// <-- CV_8U IS TOTAL BULLSHIT
	//	cvZero(histData[0]);
		for( int i=0; i < cHist->total; i++)
		{	
			float* points = (float*)cvGetSeqElem(cHist,i);
			double temp = (double)points[2];
			cvSet1D(histData[0],i,cvScalar(temp));
			printf( "Circle Center (%f,%f) R=%f N=%f\n", points[0],points[1],points[2],temp );
//			ofs << points[2] << endl;
//			cvDrawCircle(lineImg,cvPoint(points[0],points[1]),(int)points[2],cvScalarAll(127));
			cvSet1D(histData[0],i,cvScalar(points[2]/((float)m_samplePerimeter)));
		}
//		ofs.close();
		cvCalcArrHist(histData,m_CircleHist);
		cvNormalizeHist(m_CircleHist,1.00);
		for(int i=0; i<1;i++)
		{
			CvArr* temp = histData[i];
			cvRelease(&temp);
		}
		if( NULL != histData )
			delete [] histData; 
	}
	else
	{
		cvZero(m_CircleHist->bins);
	}

	//sprintf(fname,"DataPoint%iEdgeCircles.png",m_id);
	//cvSaveImage(fname,lineImg);

	if( NULL != fname )
		delete [] fname;
	cvReleaseImage(&lineImg);
}
/*******************************************************************/
vector<float> CDataPoint::MakeFeatureVector(void)
{
	vector<float> retVal;
	retVal.push_back((float)m_aspectRatio);
	retVal.push_back(m_contourArea); 
	retVal.push_back(m_contourLength);
	retVal.push_back((float)m_huMoments.hu1);
	retVal.push_back((float)m_huMoments.hu2);
	retVal.push_back((float)m_huMoments.hu3);
	retVal.push_back((float)m_huMoments.hu4);
	retVal.push_back((float)m_huMoments.hu5);
	retVal.push_back((float)m_huMoments.hu6);
	retVal.push_back((float)m_huMoments.hu7);
	if( NULL != m_LineHist )
	{
		for( int i=0; i < 6; i++ )
		{
			for( int j=0; j < 3; j++ )
			{
				retVal.push_back( cvQueryHistValue_2D(m_LineHist,i,j) );
			}
		}
	}
	if( NULL != m_CircleHist )
	{
		for( int i=0; i < 10; i++ )
		{
			retVal.push_back( cvQueryHistValue_1D(m_CircleHist,i) );
		}
	}
	return retVal;
}
/*******************************************************************/
string CDataPoint::BuildFeatureVecForFile(void)
{
	stringstream ss;
	ss << m_class << "\t" << m_path+m_image_file << "\t";
	vector<float> feats = MakeFeatureVector();
	vector<float>::iterator iter;
	for( iter = feats.begin(); iter != feats.end(); ++iter )
	{
		ss << *iter << "\t";
	}
	return ss.str();
}	
/*******************************************************************/
float* CDataPoint::GetRawFeatureVec( int &size )
{
		vector<float> fv = MakeFeatureVector();
	size = fv.size();
	float * retVal = NULL;
	retVal = new float[size];
	vector<float>::iterator iter;
	int count = 0;
	for( iter = fv.begin(); iter != fv.end(); ++iter)
	{
		retVal[count] = *iter;
		count++;
	}
	return retVal; 
}	
/*******************************************************************/